#include "cljmudx10winapp.h"
#include "cljmudx10baseapp.h"
//-------------------PUBLIC METHODS----------------------------------------------------------------------------

/******************************************
* Perform the Internal Game Loop by Calling
* Update then Render.
******************************************/
bool CDX10WindowsApplication::internGameLoop()
{
	bool tprocessresult;
	tprocessresult = this->_obj_baseapp->update();
	
	if(tprocessresult)
		return this->_obj_baseapp->render();
	return false;
}


/******************************************
* Initialise our Win 32 Window based on
* the screen settings
******************************************/
bool CDX10WindowsApplication::initialise()
{
	//Use a Boolean Flag to indicate Success
	bool tinitsuccess;
	
	//If we have no application to run inside our windows app, return false.
	if(this->_obj_baseapp == NULL)
		return false;

	//Create a bi-directional link to our Application Class
	this->_obj_baseapp->setWindowManager(this);

	//If we are this point, our base application is fine, we need to set our global pointer
	//to the base application for piping WndProc Events into our game.
	g_base_app = this->getBaseApp();

	// Initialize the windows API and construct our window instance.
	this->internInitWindows();

	// Initialize the Game Application, using th
	tinitsuccess = this->_obj_baseapp->initialise();
	if(!tinitsuccess)
		return false;

	return true;
}


/******************************************
*
*
******************************************/
void CDX10WindowsApplication::internInitWindows()
{
	WNDCLASSEX	twc;
	DEVMODE		tdevmodescrsettings;
	int			tposx;
	int			tposy;

	// Get the instance of this application.
	this->_obj_h_instance = GetModuleHandle(NULL);

	// Setup the windows class with default settings.
	twc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	twc.lpfnWndProc		= WndProc;
	twc.cbClsExtra		= 0;
	twc.cbWndExtra		= 0;
	twc.hInstance		= this->_obj_h_instance;
	twc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);
	twc.hIconSm			= twc.hIcon;
	twc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	twc.hbrBackground	= (HBRUSH)GetStockObject(BLACK_BRUSH);
	twc.lpszMenuName	= NULL;
	twc.lpszClassName	= this->_obj_baseapp->getAppName();
	twc.cbSize			= sizeof(WNDCLASSEX);
	
	// Register the window class.
	RegisterClassEx(&twc);


	// Setup the screen settings depending on whether it is running in full screen or in windowed mode.
	if(this->_obj_baseapp->isFullScreen())
	{
		this->_obj_baseapp->setScreenDimensions(GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));

		// If full screen set the screen to maximum size of the users desktop and 32bit.
		memset(&tdevmodescrsettings, 0, sizeof(tdevmodescrsettings));
		tdevmodescrsettings.dmSize       = sizeof(tdevmodescrsettings);
		tdevmodescrsettings.dmPelsWidth  = (unsigned long)this->_obj_baseapp->getScreenWidth();
		tdevmodescrsettings.dmPelsHeight = (unsigned long)this->_obj_baseapp->getScreenHeight();
		tdevmodescrsettings.dmBitsPerPel = 32;			
		tdevmodescrsettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		// Change the display settings to full screen.
		ChangeDisplaySettings(&tdevmodescrsettings, CDS_FULLSCREEN);

		// Set the position of the window to the top left corner.
		tposx = tposy = 0;
	}
	else
	{
		// If windowed then set it to the preferred screen resolution.
		int tscreenwidth  = this->_obj_baseapp->getPreferredScreenWidth();
		int tscreenheight = this->_obj_baseapp->getPreferredScreenHeight();

		// Place the window in the middle of the screen.
		tposx = (GetSystemMetrics(SM_CXSCREEN) - tscreenwidth)  / 2;
		tposy = (GetSystemMetrics(SM_CYSCREEN) - tscreenheight) / 2;
	}

	// Create the window with the screen settings and get the handle to it.
	this->_obj_h_wnd = CreateWindowEx(WS_EX_APPWINDOW,
								_obj_baseapp->getAppName(),
								_obj_baseapp->getAppName(),
								WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
								tposx,
								tposy,
								this->_obj_baseapp->getScreenWidth(),
								this->_obj_baseapp->getScreenHeight(),
								NULL,
								NULL,
								this->_obj_h_instance,
								NULL);

	// Bring the window up on the screen and set it as main focus.
	ShowWindow(this->_obj_h_wnd, SW_SHOW);
	SetForegroundWindow(this->_obj_h_wnd);
	SetFocus(this->_obj_h_wnd);

	// Hide the mouse cursor.
	ShowCursor(this->_obj_baseapp->isCursorVisible());
	return;
}

/******************************************
*
*
******************************************/
void CDX10WindowsApplication::cleanup()
{
	// Shutdown the window.
	this->internCleanupWindows();

	// Release our game application
	if(this->_obj_baseapp)
	{
		//Cleanup our game application
		this->_obj_baseapp->cleanup();
		//Delete the memory associated with our game app
		delete this->_obj_baseapp;
		// Release any remaining pointers to this class.
		g_base_app			= NULL;
		this->_obj_baseapp	= NULL;
	}
	return;
}

/******************************************
*
*
******************************************/
void CDX10WindowsApplication::internCleanupWindows()
{
	// Show the mouse cursor.
	ShowCursor(true);

	// Fix the display settings if leaving full screen mode.
	if(_obj_baseapp->isFullScreen())
		ChangeDisplaySettings(NULL, 0);

	// Remove the window.
	DestroyWindow(_obj_h_wnd);
	this->_obj_h_wnd = NULL;

	// Remove the application instance.
	UnregisterClass(_obj_baseapp->getAppName(), _obj_h_instance);
	this->_obj_h_instance = NULL;
	return;
}

/******************************************
* Our Windows Procedure Callback for 
* handling the windows application.
******************************************/
LRESULT CALLBACK WndProc(HWND pwindowhandle, UINT pmessagetype, WPARAM pwparam, LPARAM plparam)
{
	switch(pmessagetype)
	{
		// Check if the window is being destroyed.
		case WM_DESTROY:
		{
			PostQuitMessage(0);
			return 0;
		}

		// Check if the window is being closed.
		case WM_CLOSE:
		{
			PostQuitMessage(0);		
			return 0;
		}

		// All other messages pass to the concrete game implementation's WndProc Handler.
		default:
		{
			return g_base_app->customWndProc(pwindowhandle, pmessagetype, pwparam, plparam);
		}
	}
}

/******************************************
* The Application Start Method handles the
* Game Loop by integrating with the Windows
* 32 Message Event Pump.
******************************************/
void CDX10WindowsApplication::appStart()
{
	MSG  twinmsg;
	bool tapploopexit;
	bool tprocess_incomplete;
	
	// Initialize the message structure - we know all messages have a fixed size.
	ZeroMemory(&twinmsg, sizeof(MSG));
	
	// Loop until there is a quit message from the window or the user.
	tapploopexit = false;

	while(!tapploopexit)
	{
		// Handle the windows messages - we want our game to play nicely with Windows
		if(PeekMessage(&twinmsg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&twinmsg);
			DispatchMessage(&twinmsg);
		}

		// If windows signals to end the application then exit out.
		if(twinmsg.message == WM_QUIT)
			tapploopexit = true;
		else
		{
			// Otherwise do the frame processing by calling our Game loop method
			tprocess_incomplete = this->internGameLoop();
			if(!tprocess_incomplete)
			   tapploopexit = true;
		}
	}
	return;
}
